using System;
using System.Reflection;

using NUnit.Framework;
using WCSFContrib.Extensions.EventBroker;
using WCSFContrib.Extensions.Utility;

namespace WCSFContrib.Extensions.Tests.CompositeWeb.Utility
{
	[TestFixture]
	public class UtilsTests
	{
		/// <summary>
		/// Helper function to get a member info on this test class
		/// </summary>
		private static T GetMember<T>(string name) where T : MemberInfo
		{
			return (T)typeof(UtilsTests).GetMember(name, BindingFlags.Instance | BindingFlags.NonPublic)[0];
		}

		[Test]
		public void ValidateParameterless()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("BasicEvent"), //  event EventHandler BasicEvent
				 GetMember<MethodInfo>("FirstMethod")); // void firstMethod()
			Assert.IsTrue(result);
		}

		[Test]
		public void ValidateParameterless2()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("DataEvent"), // event EventHandler<DataEventArgs<string>> DataEvent
				 GetMember<MethodInfo>("FirstMethod")); // void firstMethod()
			Assert.IsTrue(result);
		}

		[Test]
		public void ValidateOneStringParameter()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("DataEvent"), // event EventHandler<DataEventArgs<string>> DataEvent
				 GetMember<MethodInfo>("OneStringParameter")); // void OneStringParameter(string s)
			Assert.IsTrue(result);
		}

		[Test]
		public void ValidateOneIntParameter()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("DataEvent"), // event EventHandler<DataEventArgs<string>> DataEvent
				 GetMember<MethodInfo>("OneIntParameter")); // void OneIntParameter(int i)
			Assert.IsFalse(result);
		}

		[Test]
		public void ValidateOneObjectParameter()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("DataEvent"), // event EventHandler<DataEventArgs<string>> DataEvent
				 GetMember<MethodInfo>("OneObjectParameter")); // void OneObjectParameter(object sender)
			// This would be true if the generic EventArg had an object parameter and why on earth would you instantiate a generic object with an 'object' generic argument?
			Assert.IsFalse(result);
		}

		[Test]
		public void ValidateTwoParameters()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("BasicEvent"), //  event EventHandler BasicEvent
				 GetMember<MethodInfo>("SecondMethod")); // void SecondMethod(object sender, EventArgs e)
			Assert.IsTrue(result);
		}

		[Test]
		public void ValidateCustomEventArgs()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("CustomEvent"), // event EventHandler<CustomEventArgs> CustomEvent
				 GetMember<MethodInfo>("CustomEventHandler")); // void CustomEventHandler(object sender, CustomEventArgs e)
			Assert.IsTrue(result);
		}

		[Test]
		public void ValidateDatasEventArgs()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("DataEvent"), // event EventHandler<DataEventArgs<string>> DataEvent
				 GetMember<MethodInfo>("DataEventHandler")); // void DataEventHandlerInt(object sender, DataEventArgs<string> e)
			Assert.IsTrue(result);
		}

		[Test]
		public void ValidateDatasEventArgsInt()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("DataEvent"), // event EventHandler<DataEventArgs<string>> DataEvent
				 GetMember<MethodInfo>("DataEventHandlerInt")); // void DataEventHandlerInt(object sender, DataEventArgs<int> e)
			Assert.IsFalse(result);
		}

		[Test]
		public void ValidateListnerForString()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("DataEvent"), // event EventHandler<DataEventArgs<string>> DataEvent
				 GetMember<MethodInfo>("DataEventListnerForString")); // void DataEventListnerForString(string s)
			Assert.IsTrue(result);
		}

		[Test]
		public void ValidateListnerForInt()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("DataEvent"), // event EventHandler<DataEventArgs<string>> DataEvent
				 GetMember<MethodInfo>("DataEventListnerForInt")); // void DataEventListnerForInt(int i)
			Assert.IsFalse(result);
		}

		[Test]
		public void ValidateOneParameterButNoGenericPublisher()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("BasicEvent"), //event EventHandler BasicEvent
				 GetMember<MethodInfo>("DataEventListnerForString")); // void DataEventListnerForString(string s)
			Assert.IsFalse(result);
		}

		[Test]
		public void ValidateCustomGenericHandlerAndMethod()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("CustomDataEventGeneric"), //event EventHandler<CustomDataEventArgs<string>> CustomDataEventGeneric
				 GetMember<MethodInfo>("CustomDataEventGenericHandler")); // void CustomDataEventGenericHandler(object sender, CustomDataEventArgs<string> e)
			Assert.IsTrue(result);
		}

		[Test]
		public void ValidateCustomGenericHandlerAndMethod_SubcribeWithInt()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("CustomDataEventGeneric"), //event EventHandler<CustomDataEventArgs<string>> CustomDataEventGeneric
				 GetMember<MethodInfo>("CustomDataEventGenericHandlerInt")); // void CustomDataEventGenericHandlerInt(object sender, CustomDataEventArgs<int> e)
			Assert.IsFalse(result);
		}

		[Test]
		public void ValidateTwoGenericArgs()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("CustomDataEventGenericArgs"), // event EventHandler<TwoCustomDataEventArgs<string, string>> CustomDataEventGenericArgs
				 GetMember<MethodInfo>("TwoCustomDataEventGenericHandler")); // void TwoCustomDataEventGenericHandlerStringInt(object sender, TwoCustomDataEventArgs<string, int> e)
			Assert.IsTrue(result);
		}

		[Test]
		public void ValidateTwoGenericArgs_NoMatch()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("CustomDataEventGenericArgs"), // event EventHandler<TwoCustomDataEventArgs<string, string>> CustomDataEventGenericArgs
				 GetMember<MethodInfo>("TwoCustomDataEventGenericHandlerStringInt")); // void TwoCustomDataEventGenericHandlerStringInt(object sender, TwoCustomDataEventArgs<string, int> e)
			Assert.IsFalse(result);
		}

		[Test]
		public void ValidateTwoGenericArgs_SubsciberMethodWithArgs_Match()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("CustomDataEventGenericArgs"), // event EventHandler<TwoCustomDataEventArgs<string, string>> CustomDataEventGenericArgs
				 GetMember<MethodInfo>("TwoParameters_StringString")); // void TwoParameters_StringString(string s1, string s2)
			Assert.IsTrue(result);
		}

		[Test]
		public void ValidateTwoGenericArgs_SubsciberMethodWithArgs_NoMatch()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("CustomDataEventGenericArgs"), // event EventHandler<TwoCustomDataEventArgs<string, string>> CustomDataEventGenericArgs
				 GetMember<MethodInfo>("TwoParameters_StringInt")); // void TwoParameters_StringInt(string s1, int i1)
			Assert.IsFalse(result);
		}

		[Test]
		public void ValidateTwoGenericArgs_SubsciberMethodWithArgs_NoMatch2()
		{
			bool result = EventUtils.ValidatePublicaterSubsciberPair(
				 GetMember<EventInfo>("CustomDataEventGenericArgs"), // event EventHandler<TwoCustomDataEventArgs<string, string>> CustomDataEventGenericArgs
				 GetMember<MethodInfo>("TwoParameters_IntString")); // void TwoParameters_IntString(int i1, string s1)
			Assert.IsFalse(result);
		}

		[Test]
		public void HasEventHandlerSignature()
		{
			Type type = GetType();
			bool result = EventUtils.HasEventHandlerSignature(type.GetMethod("SecondMethod", BindingFlags.Instance | BindingFlags.NonPublic));
			Assert.IsTrue(result); // SecondMethod(object sender, EventArgs e)

			result = EventUtils.HasEventHandlerSignature(type.GetMethod("CustomEventHandler", BindingFlags.Instance | BindingFlags.NonPublic));
			Assert.IsTrue(result); // CustomEventHandler(object sender, CustomEventArgs e) - CustomEventArgs inherit EventArgs

			result = EventUtils.HasEventHandlerSignature(type.GetMethod("DataEventHandler", BindingFlags.Instance | BindingFlags.NonPublic));
			Assert.IsTrue(result); // DataEventHandler(object sender, DataEventArgs<string> e) - DataEventArgs inherit EventArgs

			result = EventUtils.HasEventHandlerSignature(type.GetMethod("FirstMethod", BindingFlags.Instance | BindingFlags.NonPublic));
			Assert.IsFalse(result); // FirstMethod()

			result = EventUtils.HasEventHandlerSignature(type.GetMethod("OneStringParameter", BindingFlags.Instance | BindingFlags.NonPublic));
			Assert.IsFalse(result); // OneStringParameter(string s)

			result = EventUtils.HasEventHandlerSignature(type.GetMethod("OneObjectParameter", BindingFlags.Instance | BindingFlags.NonPublic));
			Assert.IsFalse(result); // OneObjectParameter(object o)
		}

		private event EventHandler BasicEvent;
		private event EventHandler<DataEventArgs<string>> DataEvent;

		private event EventHandler<CustomEventArgs> CustomEvent;
		private event EventHandler<CustomDataEventArgs<string>> CustomDataEventGeneric;
		private event EventHandler<TwoCustomDataEventArgs<string, string>> CustomDataEventGenericArgs;

		private void FirstMethod()
		{
			BasicEvent.Invoke(this, EventArgs.Empty);
		}

		private void OneStringParameter(string s)
		{ }

		private void OneIntParameter(int i)
		{ }

		private void OneObjectParameter(object o)
		{ }

		private void SecondMethod(object sender, EventArgs e)
		{
			BasicEvent.Invoke(this, EventArgs.Empty);
		}

		private void CustomEventHandler(object sender, CustomEventArgs e)
		{
			CustomEvent.Invoke(this, new CustomEventArgs());
		}

		private void DataEventHandler(object sender, DataEventArgs<string> e)
		{
			DataEvent.Invoke(this, new DataEventArgs<string>("foo")); // 
		}

		private void DataEventHandlerInt(object sender, DataEventArgs<int> e)
		{ }

		private void DataEventListnerForString(string s)
		{ }

		private void DataEventListnerForInt(int i)
		{ }

		private class CustomEventArgs : EventArgs
		{ }

		private class CustomDataEventArgs<S> : EventArgs
		{ }

		private class TwoCustomDataEventArgs<S, T> : EventArgs
		{ }

		private void CustomDataEventGenericHandler(object sender, CustomDataEventArgs<string> e)
		{
			CustomDataEventGeneric.Invoke(this, new CustomDataEventArgs<string>());
		}

		private void CustomDataEventGenericHandlerInt(object sender, CustomDataEventArgs<int> e)
		{ }

		private void TwoCustomDataEventGenericHandler(object sender, TwoCustomDataEventArgs<string, string> e)
		{
			CustomDataEventGenericArgs.Invoke(this, new TwoCustomDataEventArgs<string, string>());
		}

		private void TwoCustomDataEventGenericHandlerStringInt(object sender, TwoCustomDataEventArgs<string, int> e)
		{
			CustomDataEventGenericArgs.Invoke(this, new TwoCustomDataEventArgs<string, string>());
		}

		private void TwoParameters_StringString(string s1, string s2)
		{ }

		private void TwoParameters_StringInt(string s1, int i1)
		{ }

		private void TwoParameters_IntString(int i1, string s1)
		{ }
	}
}